package com.atguigu.spzx.order.service.Impl;

import cn.hutool.core.util.IdUtil;
import com.atguigu.spzx.feign.cart.CartFeignClient;
import com.atguigu.spzx.feign.product.ProductFeignClient;
import com.atguigu.spzx.feign.user.UserFeignClient;
import com.atguigu.spzx.model.dto.api.ApiOrderSaveDTO;
import com.atguigu.spzx.model.entity.cart.CartInfo;
import com.atguigu.spzx.model.entity.order.OrderInfo;
import com.atguigu.spzx.model.entity.order.OrderItem;
import com.atguigu.spzx.model.entity.order.UserAddress;
import com.atguigu.spzx.model.entity.product.ProductSku;
import com.atguigu.spzx.model.entity.user.UserInfo;
import com.atguigu.spzx.model.exception.GuiguException;
import com.atguigu.spzx.model.vo.common.Result;
import com.atguigu.spzx.model.vo.common.ResultCodeEnum;
import com.atguigu.spzx.model.vo.order.ApiOrderTradeVO;
import com.atguigu.spzx.order.mapper.OrderMapper;
import com.atguigu.spzx.order.service.OrderItemService;
import com.atguigu.spzx.order.service.OrderService;
import com.atguigu.spzx.util.AuthContextUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author LT
 * @create 2024-03-29-19:46
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper,OrderInfo> implements OrderService {

    @Resource
    CartFeignClient cartFeignClient;
    @Resource
    ProductFeignClient productFeignClient;
    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Resource
    UserFeignClient userFeignClient;
    @Resource
    OrderItemService orderItemService;

    @Override
    public ApiOrderTradeVO trade() {

        Result<List<CartInfo>> listResult = cartFeignClient.getallCheckCart();
        Assert.isTrue(listResult.getCode().intValue() == 200,"远程查询被选中的购物项失败");
        List<CartInfo> cartInfoList = listResult.getData();

        List<OrderItem> orderItems = cartInfoList.stream().map(cartInfo -> {
            OrderItem orderItem = new OrderItem();
            orderItem.setSkuId(cartInfo.getSkuId());
            orderItem.setSkuName(cartInfo.getSkuName());
            orderItem.setThumbImg(cartInfo.getImgUrl());
            orderItem.setSkuPrice(cartInfo.getCartPrice());
            orderItem.setSkuNum(cartInfo.getSkuNum());
            return orderItem;
        }).collect(Collectors.toList());

        //3、计算订单总金额: 每个购物项价格*购物项数量 累加
        //计算 每个购物项的小计金额  最后再累加
        BigDecimal totalAmount = orderItems.stream().map(
                orderItem -> new BigDecimal(orderItem.getSkuNum().toString()).multiply(orderItem.getSkuPrice()))
                .reduce((a,b) -> a.add(b))
                .get();
        ApiOrderTradeVO orderTradeVO = new ApiOrderTradeVO();
        orderTradeVO.setOrderItemList(orderItems);
        orderTradeVO.setTotalAmount(totalAmount);

        //幂等性校验
        //1表示从购物车页面到订单确认页
        stringRedisTemplate.opsForValue().set("spzx:order:type:"+ AuthContextUtil.get1().getId(),"1",1, TimeUnit.HOURS);
        return orderTradeVO;
    }

    @Override
    public ApiOrderTradeVO buy(Long skuId) {
        Result<ProductSku> result = productFeignClient.getBySkuId(skuId);
        Assert.isTrue(result.getCode().intValue() == 200,"远程查询立即购买商品失败");
        ProductSku productSku = result.getData();

        OrderItem orderItem = new OrderItem();
        orderItem.setSkuId(skuId);
        orderItem.setSkuName(productSku.getSkuName());
        orderItem.setThumbImg(productSku.getThumbImg());
        orderItem.setSkuPrice(productSku.getSalePrice());
        orderItem.setSkuNum(1);
        ApiOrderTradeVO orderTradeVO = new ApiOrderTradeVO();
        orderTradeVO.setTotalAmount(orderItem.getSkuPrice());
        orderTradeVO.setOrderItemList(Arrays.asList(orderItem));

        //幂等性校验
        //2表示从商品详情页面到订单确认页
        stringRedisTemplate.opsForValue().set("spzx:order:type:"+ AuthContextUtil.get1().getId(),"2",1, TimeUnit.HOURS);
        return orderTradeVO;
    }

    @Override
    public Long submitOrder(ApiOrderSaveDTO orderSaveDTO) {
        Long orderId = orderSaveDTO.getOrderItemList().get(0).getOrderId();
        if (stringRedisTemplate.hasKey("spzx:order:submit:"+orderId)){
            throw new GuiguException(ResultCodeEnum.ERROR);
        }
        stringRedisTemplate.opsForValue().set("spzx:order:submit:"+orderId,"1",30,TimeUnit.MINUTES);
        UserInfo userInfo = AuthContextUtil.get1();
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setUserId(userInfo.getId());
        orderInfo.setNickName(userInfo.getNickName());
        String orderNo = IdUtil.getSnowflake().nextIdStr();
        orderInfo.setOrderNo(orderNo);

        orderSaveDTO.getOrderItemList().forEach(orderItem -> {
            Result<ProductSku> result = productFeignClient.getBySkuId(orderItem.getSkuId());

            if (result.getCode().intValue() !=200){
                throw new GuiguException(ResultCodeEnum.ERROR);
            }
            //校验价格是否变动
            ProductSku sku = result.getData();
            if (orderItem.getSkuPrice().compareTo(sku.getSalePrice())!=0){
                throw new GuiguException(ResultCodeEnum.ORDER_SUBITM_PRICE_ERROR);
            }
            //校验库存是否足够
            if ((sku.getStockNum()-orderItem.getSkuNum())<0){
                throw new GuiguException(ResultCodeEnum.ORDER_SUBITM_STOCK_ERROR);
            }

        });
        BigDecimal totalAmount = orderSaveDTO.getOrderItemList().stream().map(orderItem ->
                        new BigDecimal(orderItem.getSkuNum())
                                .multiply(orderItem.getSkuPrice()))
                .reduce((a, b) -> a.add(b))
                .get();
        orderInfo.setTotalAmount(totalAmount);
        orderInfo.setCouponAmount(new BigDecimal(0));
        orderInfo.setOriginalTotalAmount(totalAmount);
        orderInfo.setFeightFee(orderSaveDTO.getFeightFee());
        orderInfo.setOrderStatus(0);

        //查询收件人信息
        Result<UserAddress> result = userFeignClient.getUserAddress(orderSaveDTO.getUserAddressId());
        if (result.getCode().intValue()!=200){
            throw new GuiguException(ResultCodeEnum.ERROR);
        }

        UserAddress userAddress = result.getData();
        orderInfo.setReceiverName(userAddress.getName());
        orderInfo.setReceiverPhone(userAddress.getPhone());
        orderInfo.setReceiverTagName(userAddress.getTagName());

        orderInfo.setReceiverProvince(Long.parseLong(userAddress.getProvinceCode()));
        orderInfo.setReceiverCity(Long.parseLong(userAddress.getCityCode()));
        orderInfo.setReceiverDistrict(Long.parseLong(userAddress.getDistrictCode()));
        orderInfo.setReceiverAddress(userAddress.getFullAddress());
        orderInfo.setRemark(orderSaveDTO.getRemark());

        baseMapper.insert(orderInfo);

        //获取orderId
        Long orderInfoId = orderInfo.getId();

        //保存订单项
        orderSaveDTO.getOrderItemList().forEach(orderItem -> {
            orderItem.setOrderId(orderInfoId);
        });
        orderItemService.saveBatch(orderSaveDTO.getOrderItemList());

        String type = stringRedisTemplate.opsForValue().get("spzx:order:type:" + AuthContextUtil.get1().getId());

        if ("1".equals(type)){
            cartFeignClient.clearCheckedCart();
        }
        return orderInfoId;
    }

    @Override
    public PageInfo<OrderInfo> listByStatus(Integer pageNum, Integer pageSize, Integer orderStatus) {

        Page<OrderInfo> page = new Page<>(pageNum, pageSize);
        List<OrderInfo> orderInfos = baseMapper.selectOrderPageStatus(page,orderStatus);
        PageInfo<OrderInfo> pageInfo = new PageInfo<>();
        pageInfo.setList(orderInfos);
        pageInfo.setPageNum(pageNum);
        pageInfo.setPageSize(pageSize);
        pageInfo.setTotal(page.getTotal());
        return pageInfo;
    }

    @Override
    public OrderInfo getByOrderInfoOrderNo(Long orderNo) {
        OrderInfo orderInfo = this.getOne(Wrappers.lambdaQuery(OrderInfo.class)
                .eq(OrderInfo::getIsDeleted, 0)
                .eq(OrderInfo::getOrderNo, orderNo));
        List<OrderItem> orderItems = orderItemService.list(Wrappers.lambdaQuery(OrderItem.class)
                .eq(OrderItem::getIsDeleted, 0)
                .eq(OrderItem::getOrderId, orderInfo.getId()));
        orderInfo.setOrderItemList(orderItems);
        return orderInfo;
    }

    @Override
    public void updateStockAndSale(String orderNo) {
        //1、查询订单所有的订单项列表
        //1、先查询orderInfo:
        OrderInfo orderInfo = baseMapper.selectOne(Wrappers.lambdaQuery(OrderInfo.class)
                .eq(OrderInfo::getOrderNo, orderNo));
        //更新订单支付方式和支付状态。

        // 数据库表索引失效问题：mybatis sql中的参数使用的是预编译的方式来填充  最终传入的值会转换为 字段需要的类型
        List<OrderItem> orderItems = orderItemService.list(Wrappers.lambdaQuery(OrderItem.class)
                .eq(OrderItem::getOrderId, orderInfo.getId()));
        //3、更新每个订单项对应的sku的库存和销量
        //将orderItems要更新的 sku的id和数量 转为map
        Map<Long, Integer> map = orderItems.stream().collect(Collectors.toMap(OrderItem::getSkuId, OrderItem::getSkuNum));
        //4、远程调用product服务的接口 更新sku的销量库存
        productFeignClient.batchUpdateSkuStockAndSale(map);

    }

    @Override
    public void updatePayTypeAndOrderStatus(Integer payType, String paymentStatus, String orderNo) {
        //1、先查询orderInfo:
        System.out.println(paymentStatus);
        OrderInfo orderInfo = baseMapper.selectOne(Wrappers.lambdaQuery(OrderInfo.class)
                .eq(OrderInfo::getOrderNo, orderNo));
        orderInfo.setOrderStatus(Integer.parseInt(paymentStatus));
        orderInfo.setPayType(payType);
        this.updateById(orderInfo);
    }


}
